42. Two means of “typename"

template <class T> class Widget;
template <typename T> class Widget;
템플릿의 타입 매개변수를 선언할 때, class와 typename와 동일하게 사용된다.
template <typename C> // 릿 릿
void print2nd(const C& container){
if(container.size()>=2){
C::const_iterator iter(container.begin()); // compile error
++iter;
int value=*iter;
std::cout<<value;
}
}
C::const_iterator는 템플릿 매개변수에 종속된 타입으로 의존 이름(dependent name)이라고 한다.
value는 템플릿 매개변수와 상관이 없는 비의존 이름(non-dependentname)

하지만, 컴파일러는 C::const_iterator가 타입이름인지 알지 못한다.
(실제로 const_iterator가 타입이 아닌 정적 데이터 멤버로 정의되어 있을 수도 있음)

C++에서 중첩 의존 이름을 만났을 때, 사용자가 직접 이를 타입이라고 명시하지 않으면,
해당 이름을 타입으로 사용하지 않도록 가정한다.

typename 키워드를 사용해서 해당 의존 이름이 타입임을 명시해 주어야 한다.
template <typename C>
void print2nd(const C& container){
if(container.size()>=2){
typename C::const_iterator iter(container.begin());
// ...
}
}
템플릿 안에서 중첩 의존 이름을 참조할 경우, typename 키워드를 붙여줘야 한다.
(중첩 의존 이름이 아닌 경우, 사용하지 말것)

단, 중첩 의존 타입 이름이 기본 클래스의 리스트에 있거나 멤버 초기화 리스트 내의 기본 클래스 식별자로 있는 경우,
typename 을 사용하면 안된다.
template <typename T>
class Derived: public Base<T>::Nested{ //
public:
explicit Derived(int x): Base<T>::Nested(x){ //
typename Base<T>::Nested temp;
// ...
}
// ...
};
혹은 typedef로 사용하는 type의 이름을 다르게 호출하고 싶은 경우, 사용한다.(using과 동일)

C++에서 typedef로 지역 이름(멤버 이름)을 사용하는 것을 관례로 한다
template <typename IterT>
void workWithIterator(iterT iter){
typename std::iterator_traits<IterT>::value_type temp(*iter);
// ...
}
// typedef
template <typename IterT>
void workWithItertaor(IterT iter){
typedef typename std::iterator_traits<IterT>::value_type value_type;
value_Type temp(*iter);
// ...
}